package top.xiangqifu.springboot2_auth.service.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import top.xiangqifu.springboot2_auth.base.BaseDataResult;
import top.xiangqifu.springboot2_auth.base.BaseResult;
import top.xiangqifu.springboot2_auth.dao.TbAuthApiDAO;
import top.xiangqifu.springboot2_auth.dao.TbAuthRoleApiDAO;
import top.xiangqifu.springboot2_auth.dao.TbAuthUserDAO;
import top.xiangqifu.springboot2_auth.dao.TbAuthUserInfoDAO;
import top.xiangqifu.springboot2_auth.entity.*;
import top.xiangqifu.springboot2_auth.service.AuthService;
import top.xiangqifu.springboot2_auth.utils.AuthInfoUtils;
import top.xiangqifu.springboot2_auth.utils.JwtUtils;
import top.xiangqifu.springboot2_auth.utils.Utils;
import top.xiangqifu.springboot2_auth.vo.PwdVo;
import top.xiangqifu.springboot2_auth.vo.UserVo;

import java.nio.charset.StandardCharsets;
import java.util.Random;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {

    private final TbAuthUserDAO tbAuthUserDAO;
    private final TbAuthApiDAO tbAuthApiDAO;
    private final TbAuthRoleApiDAO tbAuthRoleApiDAO;
    private final TbAuthUserInfoDAO tbAuthUserInfoDAO;

    private static final String RAND_SIRINGS = "abcdefjhijklmnopqrstyvwxyz1234567890";


    public String makeRandString(int length) {
        //字符串构造器，用于大量拼接字符
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            sb.append(RAND_SIRINGS.charAt(random.nextInt(RAND_SIRINGS.length())));
        }
        return sb.toString();
    }


    @Override
    public BaseDataResult<UserVo> queryUser() throws Exception {
        UserVo userVo = new UserVo();
        AuthInfo authInfo = AuthInfoUtils.authInfo();
        userVo.setUser(tbAuthUserDAO.queryByKey(authInfo.getUserId()));
        userVo.setInfo(tbAuthUserInfoDAO.queryByKey(authInfo.getUserId()));
        BaseDataResult<UserVo> result = new BaseDataResult<>();
        result.setSuccess(true);
        result.setCode(200);
        result.setMessage("");
        result.setData(userVo);
        return result;
    }

    @Override
    public BaseResult<String> reg(UserVo userVo) throws Exception {
        BaseResult<String> result = new BaseResult<>();
        TbAuthUser check = tbAuthUserDAO.queryByName(userVo.getUser());
        if (check != null) {
            result.setCode(500);
            result.setSuccess(false);
            result.setMessage("用户名已经存在");
            return result;
        }

        //需要生成密码盐信息对密码进行加密
        String salt = makeRandString(6);
        //密码一次，md5加密一次
        String pwd = userVo.getUser().getPassword();
        pwd = DigestUtils.md5DigestAsHex(pwd.getBytes(StandardCharsets.UTF_8));
        //二次带密码盐加密，防止彩虹表还原信息
        pwd = pwd + salt;
        pwd = DigestUtils.md5DigestAsHex(pwd.getBytes(StandardCharsets.UTF_8));
        //添加基本的用户信息
        userVo.getUser().setPassword(pwd);
        userVo.getUser().setSalt(salt);
        userVo.getUser().setRoleId(2);
        int i = tbAuthUserDAO.add(userVo.getUser());
        //如果添加失败就会中断流程，返回错误应答
        if (i != 1) {
            result.setCode(500);
            result.setSuccess(false);
            result.setMessage("用户信息添加失败，请稍后重试");
            return result;
        }
        //添加用户附加信息，确保一对一关系的数据正常
//        TbAuthUserInfo tbAuthUserInfo=new TbAuthUserInfo();
        //拿到第一步添加的主键信息写入到附加信息中
        userVo.getInfo().setUserId(userVo.getUser().getUserId());
        userVo.getInfo().setNickname(userVo.getInfo().getNickname());
        userVo.getInfo().setSex("n");
        i = tbAuthUserInfoDAO.add(userVo.getInfo());
        result.setSuccess(i == 1);
        result.setMessage(i == 1 ? "用户添加成功" : "用户添加失败");
        result.setCode(i == 1 ? 200 : 500);
        return result;
    }

    @Override
    public boolean checkAuth() {
        //检测当前用户是否拥有路径访问权限
        AuthInfo authInfo = AuthInfoUtils.authInfo();
        //查询当前访问路径是否被数据库管理
        TbAuthApi tbAuthApi = new TbAuthApi();
        tbAuthApi.setUrl(authInfo.getMappingPath());
        tbAuthApi.setMethod(authInfo.getMethod());
        tbAuthApi = tbAuthApiDAO.queryByUrl(tbAuthApi);
        if (tbAuthApi == null) {
            //不被管理的路径直接跳过
            return true;
        }
        if (authInfo.getUserId() == null) {
            //请求中没有登入信息
            return false;
        }
        //校验当前用户是否有用户菜单访问权限
        TbAuthRoleApi tbAuthRoleApi = new TbAuthRoleApi();
        tbAuthRoleApi.setApiId(tbAuthApi.getApiId());
        // 角色传入的是用户id，查询会将用户id转换成对应的角色id
        tbAuthRoleApi.setRoleId(authInfo.getUserId());
        tbAuthRoleApi = tbAuthRoleApiDAO.queryByUser(tbAuthRoleApi);
        if (tbAuthRoleApi == null) {
            // 没有记录就没有通过授权
            return false;
        }
        return true;

    }

    @Override
    public BaseResult login(TbAuthUser user) {
        //判断用户是否存在
        TbAuthUser check = tbAuthUserDAO.queryByName(user);
        if (check == null) {
            return BaseResult.fail("用户不存在");
        }
        //判断用户是否禁用
        if ("n".equalsIgnoreCase(check.getEnable())) {
            return BaseResult.fail("用户已禁用");
        }
        //校验密码
        String pwd = Utils.saltMd5(user.getPassword(), check.getSalt());
        if (!check.getPassword().equalsIgnoreCase(pwd)) {
            return BaseResult.fail("密码错误");
        }
        //用登入用户id生成jwt的token //user,userpwd
        String token = JwtUtils.makeUserIdToken(check.getUserId());
        BaseResult result = BaseResult.ok("登入成功");
        //递交token给客户
        result.setToken(token);
        return result;
    }

    @Override
    public BaseResult updatePwd(PwdVo pwdVo) {
        AuthInfo authInfo = AuthInfoUtils.authInfo();
        TbAuthUser users = new TbAuthUser();
        pwdVo.getUser().setUserId(authInfo.getUserId());
        users = (tbAuthUserDAO.queryByKey(authInfo.getUserId()));
        //校验密码
        String pwd = Utils.saltMd5(pwdVo.getOldpwd(), users.getSalt());
        if (!users.getPassword().equalsIgnoreCase(pwd)) {
            return BaseResult.fail("密码错误");
        }
        //更新密码
        String pwd1 = Utils.saltMd5(pwdVo.getUser().getPassword(), users.getSalt());
        pwdVo.getUser().setPassword(pwd1);
        int i = tbAuthUserDAO.updatePwd(pwdVo.getUser());
        if (i != 1) {
            return BaseResult.ok("密码修改失败");
        }

        return BaseResult.ok("密码修改成功");
    }

    @Override
    public BaseResult<TbAuthUserInfo> update(TbAuthUserInfo userInfo) {
        AuthInfo authInfo = AuthInfoUtils.authInfo();
        userInfo.setUserId(authInfo.getUserId());
        TbAuthUserInfo userInfo1 = tbAuthUserInfoDAO.queryByKey(userInfo.getUserId());
        if (userInfo.getNickname() == null || userInfo.getNickname() == "".toString()) {
            userInfo.setNickname(userInfo1.getNickname());
        }
        if (userInfo.getSex() == null || userInfo.getSex() == "".toString()) {
            userInfo.setSex(userInfo1.getSex());
        }
        if (userInfo.getEmail() == null || userInfo.getEmail() == "".toString()) {
            userInfo.setEmail(userInfo1.getEmail());
        }
        if (userInfo.getPhone() == null || userInfo.getPhone() == "".toString()) {
            userInfo.setPhone(userInfo1.getPhone());
        }
        if (userInfo.getImgurl() == null || userInfo.getImgurl() == "".toString()) {
            userInfo.setImgurl(userInfo1.getImgurl());
        }
        int i = tbAuthUserInfoDAO.update(userInfo);
        if (i != 1) {
            return BaseResult.ok("用户附加信息修改失败");
        }
        return BaseResult.ok("用户附加信息修改成功");
    }


}
